package com.df.my_net_game.game_rpc;

import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
import com.df.my_net_game.common.config.MethodMetaInfo;
import com.df.my_net_game.game_rpc.client.GRpcClientHandler;
import com.df.my_net_game.game_rpc.codec.GRpcCodec;
import com.df.my_net_game.game_rpc.utils.TypeUtils;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Promise;
import lombok.Data;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 服务节点实现
 * 1. 管理节点连接状态
 * 2. 处理同步/异步消息发送
 * 3. 实现连接健康检查
 */
@Data
public class ServerNode {
    private final String address;
    private String ip;
    private  Integer port;
    private volatile Channel channel;
    private volatile boolean healthy = true;
    private String serviceName;
    private long lastActiveTime = System.currentTimeMillis();
    private ReentrantLock lock = new ReentrantLock();
    Bootstrap bootstrap = new Bootstrap();
    EventLoopGroup group = null;
    public ServerNode(String address) {
        this.address = address;
        String[] split = address.split(":");
        this.ip = split[0];
        this.port = Integer.parseInt(split[1]);
    }
    //TODO 超时移除
    private ConcurrentHashMap<Long,Promise<EzGameMsg>> reqCache = new ConcurrentHashMap<>();
    //TODO 时间轮来移除超时的请求

    public Promise<EzGameMsg> sendMsgAync(MethodMetaInfo methodMetaInfo, Object[] args) throws Exception {
        return sendMsgDo(methodMetaInfo, args, true);
    }

//    public Object sendMsgSync(MethodMetaInfo methodMetaInfo, Object[] args) {
//        try {
//            return sendMsgDo(methodMetaInfo, args, false).sync().get();
//        } catch (Exception e) {
//            throw new RuntimeException("RPC call failed", e);
//        }
//    }


    private Promise<EzGameMsg> sendMsgDo(MethodMetaInfo methodMetaInfo, Object[] args, boolean async) throws Exception {
        if(!isHealthy()){
            throw new RuntimeException("channel  not healthy");
        }
        checkAndInitConnection();
        if(channel==null || !isHealthy()){
            throw new RuntimeException("channel is null or not healthy");
        }
        //TODO 看下promise怎么创建对象的
        Promise<EzGameMsg> promise = channel.eventLoop().newPromise();
        //TODO 请求唯一id要与promise进行映射,以便后续消息返回时找到到请求(异步的也要超时?)
        try {
            EzGameMsg request = createRequest(methodMetaInfo, args);
//            reqCache.put(request.getHeader().getReqId(),promise);
            ChannelFuture writeFuture = channel.writeAndFlush(request);
            
            writeFuture.addListener(future -> {
                if (!future.isSuccess()) {
                    promise.setFailure(future.cause());
                    markUnhealthy();
                }
            });
            
//            if (!async) {
//                writeFuture.await(methodMetaInfo.getTimeout(), TimeUnit.MILLISECONDS);
//            }
        } catch (Exception e) {
            e.printStackTrace();
            //TODO 细分，什么时候才标记服务器为非健康状态
            promise.setFailure(e);
        }
        return promise;
    }

    private EzGameMsg createRequest(MethodMetaInfo methodMetaInfo, Object[] args) throws Exception {
        EzGameMsg msg = new EzGameMsg();
        GRpcHeader header = new GRpcHeader();
//        private Integer reqId;
//        private Integer cmdId;
//        private Integer clientType;//客户端类型 0玩家客户端 1serverNode客户端
//        private Integer clientIp;//
//        private Integer serverNodeClientIp;//
//        private Integer msgType;//1 请求 ；2响应
        //TODO 分布式日志追踪
        //TODO 唯一id： 雪花算法
        //long 64位
        //
//        header.setReqId(GRpcServiceMgr.nextSnowId());
        header.setCmdId(methodMetaInfo.getCmdId());
//        header.setClientType(1);
        //TODO 客户端的ip获取,一般网关转发才带这个
//        header.setClientIp(0);
        header.setMsgType(GRpcMsgTypeEnum.Req.msgType());
        msg.setHeader(header);
        if(methodMetaInfo.getParameterType()!=null){
            if(args.length>0){
                if(methodMetaInfo.isParamIsBaseType()){
                    Object paramData = TypeUtils.getWrapperParam(methodMetaInfo.getParameterWrapperType(),args[0]);
                    if(paramData!=null){
                        Codec codec = ProtobufProxy.create(methodMetaInfo.getParameterType());
                        msg.setBodyBytes(codec.encode(paramData));
                    }
                }else {
                    Codec codec = ProtobufProxy.create(methodMetaInfo.getParameterType());
                    if(args[0]!=null){
                        msg.setBodyBytes(codec.encode(args[0]));
                    }
                }

                //如果是基本类型，则进行包装后序列化
                //不是基本类型，直接使用序列序列化方式进行序列化
            }
        }else {
            msg.setBodyBytes(new byte[0]);
        }
        return msg;
    }
    private  void checkAndInitConnection() throws Exception {
        if(channel != null && channel.isActive()) {
            return;
        }
        lock.lock();
        try {
            if(channel != null && channel.isActive()) {
                return;
            }
            // 实际网络连接实现需要根据使用的网络框架实现
            // 这里只是示例伪代码
            this.channel = connectToServer();
            if(channel!=null && channel.isActive()) {
                this.healthy = true;
            }

        }catch (Exception e){
            throw e;
        }finally {
            lock.unlock();
        }
    }

    public boolean checkAlive(long timeoutMs) {
        try {
            // 实现实际的心跳检测逻辑
            // 示例伪代码：
//            ChannelFuture future = channel.writeAndFlush(new HeartbeatPing())
//                .await(timeoutMs, TimeUnit.MILLISECONDS);
//            return future.isSuccess();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private Channel connectToServer() throws InterruptedException {
        // 实现具体的网络连接建立逻辑
        // 返回有效的Channel对象
        //TODO 创建netty客户端，添加handler，添加心跳（断开：注册中心下线和网络异常下线）
        try {
            if(group==null){
                group = new NioEventLoopGroup();
                GRpcClientHandler clientHandler = new GRpcClientHandler(this);
                bootstrap.group(group)
                        .channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) {
                                ChannelPipeline pipeline = ch.pipeline();
                                pipeline.addLast(new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS));
                                pipeline.addLast(new GRpcCodec());
                                pipeline.addLast(clientHandler);
                            }
                        });
            }

            ChannelFuture future = bootstrap.connect(ip, port).sync();
            channel = future.channel();
        }catch (Exception e){
            throw e;
        }

        return channel; // 实际实现需要返回有效连接
    }

    public void markUnhealthy() {
        this.healthy = false;
    }

    public void close() {
        if (channel != null) {
            channel.close();
            channel = null;
        }
        if(group!=null) {
            group.shutdownGracefully();
        }
    }

    // Getters and Setters
    public String getAddress() { return address; }
    public boolean isHealthy() { return healthy; }
    public void setServiceName(String serviceName) { this.serviceName = serviceName; }
}

// 心跳请求对象
class HeartbeatPing {}
